# -*- coding: utf-8 -*- 

import socket, sys, threading,time
import wx 
from pyDemin import * 
from pyD import *
host = '127.0.0.1' 
port = int(sys.argv[1])#80037
conf=[]
maxj=3  #nombre max de joueurs , nb necessaire pour debuter la partie
conn_client={} #dictionnaire des connexions clients 
dico={} 
lesnoms={} # dictionnaire pour les noms des joueurs
lesgrilles={} # dictionnaires des grilles joueurs
ferme=0
verrou=threading.Lock()


class threadconnexion(threading.Thread) :  
 
#creation de la socket puis connexion 
    def __init__(self,conn) : #conn reference de con 
        threading.Thread.__init__(self) 
        self.connexion=conn 
        
 
#actions du serveur en reponse au client  
    def run(self):
        nom=self.getName()
        grillechar=''#grille sous forme de caractere, pour la send par socket
         
        if len(conn_client)<maxj:
            conn_client[nom]=self.connexion
         
        while 1:
            msg = self.connexion.recv(1024) #recoit du client 
            msg=msg.split(',')
            print "**%s** > %s" % (nom,msg[0]) 
            if msg[0]=='FIN' or msg[0].upper()=="FIN" or msg[0]=="" :
                self.findeconnexion(nom)
                break
            elif msg[0]=='0': #'clientOK':
                if ferme<>1:
                    conf.append(nom+'ok')
                    self.clientOK(nom)

# confirmation des clients:
                
            elif msg[0]=="OK":                
                self.OK(msg,nom)
                         
# Requête d'envoi du nb de joueurs:
            elif msg[0]=="nbj":
                print "nbj ok demanded"
               # print conn_client
                for cli in conn_client:#on envoie l'info à tout le monde !
                    conn_client[cli].send("nbj."+str(len(conn_client))+"."+str(maxj))
       
# cas du clic gauche d'un client:
            elif msg[0]=="L":
                self.clientclikG(msg,nom)
                #on renvoit la grille modifiee au client. La modification a aussi ete enregistree ds notre dictionnaire

# cas du clic droit d'un client
            elif msg[0]=='R':
                self.clientclikD(msg,nom)
                #on renvoit la grille modifiee au client. La modification a aussi ete enregistree ds notre dictionnaire

# demande d'informations de la part du client
            elif msg[0]=='info':
                self.sendinfo(nom)
        self.connexion.close() 
   
# fermeture de la connexion
    def findeconnexion(self,nom):
        conn_client[nom].close()
        del conn_client[nom]
        del lesgrilles[nom]

	for cli in conn_client:
            conn_client[cli].send("M, " + "%s"%(nom)+" a quitte la partie")
        print "client %s deconnecte "% nom + 'il reste %d joueurs'% len(conn_client)
         
        return 0
    
      



    def clientOK(self,nom):
         
        if len(conn_client)>maxj : # verification du nombre de joueurs pour le lancement de la partie
            ferme=1
        elif len(conn_client)<maxj:
            for cli in conn_client:
                conn_client[cli].send("M, " + "il y a "+ "%d"%len(conn_client)+" joueurs, patientez") 
            for cli in conn_client:
                if cli != nom: # ne pas le renvoyer a l'emetteur
                    conn_client[cli].send("M, "+"%s"%(nom)+'a rejoint la partie')
            self.connexion.send("il y a"+"%d"%len(conn_client)+"joueurs, patientez") 
        elif len(conn_client)==maxj:
            print("%d"%len(conf))
#lorsque le nb de joueurs est ok pr commencer une partie , creation de la grille, envoie des parametres+grille
            for cli in conn_client:
                if cli != nom: # ne pas le renvoyer a l'emetteur
                    conn_client[cli].send("M, " +"%s"%(nom)+'a rejoint la partie')
                if len(conf)==maxj:
                    conn_client[cli].send("M, "+"Begin party ?")
         
# confirmation du client et lancement de la partie
    def OK(self,msg,nom,l,L,nm):
        print("inOK")
         
        if len(conn_client)==maxj:
            dico[nom]=msg[0]
            lesnoms[nom]=msg[1]
            print msg
            print ("%d"%len(dico))
            if len(dico)==len(conn_client):
                
                Demi=pyDemin(l,L,nm)#creation de l'objet demineur, et donc de la grille
                Demi.comptemine()	
                                               
                print("grille envoyee")
# il faut sauvegarder une grille pour chaque joueur pour suivre leurs avancees
#on cree un dico de grille
                for cli in conn_client:
                    lesgrilles[cli]=pyDemin(l,L,nm)
                    lesgrilles[cli].inf=Demi.inf.copy()
#pour copier un numpy le [:] ne fonctionne pas, mais il existe une methode prevue pour
                    lesgrilles[cli].deco=Demi.deco.copy()
# pour chaque client, on fait attention a copier un objet et pas un pointeur
                conn_clientsave=conn_client.copy()
                for cli in conn_clientsave:
                    conn_client[cli].send('G,'+'%d , %d, %d '%(l,L,nm))#+grillechar)

# action suite au clic gauche d'un joueur
    def clientclikG(self,msg,nom):
        x,y=[msg[1],msg[2]]
        
        if lesgrilles[nom].encours==0:
            k=0
            if lesgrilles[nom].deco[int(x),int(y)]!=2: # on verifie que la case n'est pas decouverte
                a=lesgrilles[nom].devoil(int(x),int(y))#on la devoile
                lesgrilles[nom].recursion(int(x),int(y))#et on devoile celles autour ne contenant pas d'informations
                if a!=-1:# on verifie que la case n'est pas une mine
                    grillechar=''
                    #print lesgrilles[nom].inf
                    for i in range(lesgrilles[nom].l):
                        for j in range(lesgrilles[nom].L):
# on reforme la grille a envoyer au client avec
                            if lesgrilles[nom].deco[i,j]==1:  
                                grillechar=grillechar + ",%d"%lesgrilles[nom].inf[i,j] #le nb de mines voisines
                            elif lesgrilles[nom].deco[i,j]==2 :
                                grillechar=grillechar + ",-2"  # -2 si la case est deja drapeautee
                            else:
                                grillechar=grillechar + ",-1"   # -1 si la case n'est pas encore decouverte
                                                 
                    conn_client[nom].send('Gupdate'+grillechar)#on envoie au client la nouvelle grille 
                   
                    
                else:# si un joueur a perdu
                    lesgrilles[nom].encours=1
                    conn_client[nom].send("PERDU")
                    self.sendinfo(nom)
            else : 
                conn_client[nom].send("PRINT,Case drapeaute")
            for i in range(lesgrilles[nom].l):
                for j in range(lesgrilles[nom].L):
                    if lesgrilles[nom].deco[i,j]==1:
                        k+=1
            if k==(lesgrilles[nom].l*lesgrilles[nom].L-lesgrilles[nom].nm):# si un joueur a gagne
                lesgrilles[nom].encours=2
                conn_client[nom].send("GAGNE")
                self.sendinfo(nom)
                for cli in conn_client:
                    if cli != nom: # ne pas le renvoyer a l'emetteur
                        conn_client[cli].send("PERDU"+"%s"%(nom)+'a gagné la partie')# on envoie aux autres joueur l'information
                        lesgrilles[cli].encours=1

    def clientclikD(self,msg,nom):  #on modifie le deco pour drapeaute ou dedrapeaute la case cliquee et on envoie la grille update
        x,y=[msg[1],msg[2]]
         
        if lesgrilles[nom].deco[int(x),int(y)]==0:
            lesgrilles[nom].deco[int(x),int(y)]=2
        elif lesgrilles[nom].deco[int(x),int(y)]==2:
            lesgrilles[nom].deco[int(x),int(y)]=0

        grillechar=''

        for i in range(lesgrilles[nom].l):
            for j in range(lesgrilles[nom].L):
# on reforme la grille a envoyer au client avec
                if lesgrilles[nom].deco[i,j]==1: 
                    grillechar=grillechar + ",%d"%lesgrilles[nom].inf[i,j] #le nb de mines voisines
                elif lesgrilles[nom].deco[i,j]==2 :
                    grillechar=grillechar + ",-2"  # -2 si la case est deja drapeautee
                else:
                    grillechar=grillechar + ",-1"   # -1 si la case n'est pas encore decouverte
                                                     
        conn_client[nom].send('Gupdate'+grillechar)#on envoie au client la nouvelle grille 
                     
#envoie de l'avancement de la partie
    def sendinfo(self,nom):
        nbj=len(conn_client)
        k=0
        minedecouverte=k
        msg=',%d'%nbj
        for cli in conn_client: 
            statut=lesgrilles[cli].encours
            for i in range(lesgrilles[cli].l):
                for j in range(lesgrilles[cli].L):
                    if lesgrilles[cli].deco[i,j]==1:
                        k+=1
            minedecouverte=k
            msg+=  ",%s"%lesnoms[cli]
            msg+= ",%d"%statut 
            msg+= ",%d"%minedecouverte
        for cli in conn_client:
            conn_client[cli].send('inf'+msg)
        print msg


# Initialisation du serveur - Mise en place du socket :



mySocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
    mySocket.bind((host,port))
except socket.error:
    print "La liaison du socket a l'adresse choisie a echoue."
    sys.exit()
print "Serveur pret, en attente de requetes ..."
mySocket.listen(5)

while 1:
    connexion, adresse = mySocket.accept()
# Creer un nouvel objet thread pour gerer la connexion :
    th = threadconnexion(connexion)
    th.start()
    it = th.getName() # identifiant du thread
    
    conn_client[it] = connexion
     
